const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const User = require('../models/userModel')
const { redisClient, getCodeKey } = require('../config/db')
const secretKey = require('../config/index')
const Captcha = require('svg-captcha')
const { sendVerificationEmail } = require('../utils/email')
const { desensitizePhone } = require('../utils/lib')
const moment = require('moment')

class UserController {
    /**
     * @swagger
     * /getCaptcha:
     *   get:
     *     summary: 获取验证码接口
     *     description: 用于登录验证
     *     tags: [登录验证码]
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: {
     *                     captchaId: "captchaId",
     *                     "captchaUrl": ""
     *                   }
     *                 msg:
     *                   type: string
     *                   example: "验证码获取成功！"
     */
    // 获取验证码
    static async getCaptcha(ctx) {
        try {
            // 创建验证码
            const captcha = Captcha.create({
                width: 100,
                height: 38,
                size: 4, // 验证码长度
                ignoreChars: '0o1i', // 忽略容易混淆的字符
                noise: 2, // 干扰线数量
                color: true, // 彩色验证码
                // background: '#f0f0f0' // 背景颜色
            })

            // 将验证码文本存储到 Redis，设置 5 分钟过期时间
            const captchaId = Date.now() + Math.random().toString(36).substr(2)
            await redisClient.setEx(`captcha:${captchaId}`, 5 * 60, captcha.text.toLowerCase())

            // 设置响应头
            ctx.set('Content-Type', 'image/svg+xml')

            // 返回验证码 ID 和 SVG 图像
            ctx.status = 200
            ctx.body = {
                code: 200,
                data: {
                    captchaId,
                    captchaUrl: captcha.data
                },
                msg: '验证码获取成功！'
            }
        } catch (error) {
            ctx.body = {
                code: 500,
                data: null,
                msg: '生成验证码失败！'
            }
        }
    }

    /**
     * @swagger
     * /user/register:
     *   post:
     *     summary: 用户注册接口
     *     description: 用于用户注册
     *     tags: [注册]
     *     parameters:
     *       - name: username
     *         type: string
     *         required: true
     *         description: 用户账号
     *       - name: password
     *         type: string
     *         required: true
     *         description: 密码
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: null
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "注册成功！"
     */
    // 注册
    static async register(ctx) {
        const { username, password } = ctx.request.body

        try {
            let user = await User.findByUsername(username)

            if (user) {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '用户已存在！'
                }

                return
            }

            // 用户不存在，去注册
            let newPwd = bcrypt.hashSync(password, 10) // 对密码进行加密处理
            let result = await User.create({ username, password: newPwd })

            if (result) {
                ctx.body = {
                    code: 200,
                    data: null,
                    msg: '注册成功！'
                }
            }
        } catch (error) {
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员：' + error
            }
        }
    }

    /**
     * @swagger
     * /user/login:
     *   post:
     *     summary: 用户登录接口
     *     description: 用于用户登录
     *     tags: [登录]
     *     parameters:
     *       - name: username
     *         type: string
     *         required: true
     *         description: 用户账号
     *       - name: password
     *         type: string
     *         required: true
     *         description: 密码
     *       - name: captchaId
     *         type: string
     *         required: true
     *         description: 验证码id
     *       - name: captchaText
     *         type: string
     *         required: true
     *         description: 验证码
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: {
     *                      accessToken: '访问数据token',
     *                      refreshToken: '刷新令牌token'
     *                   }
     *                 msg:
     *                   type: string
     *                   example: "登录成功！"
     */
	// 用户登录（账号密码登录）
	static async login(ctx) {
		try {
			const { username, password, captchaId, captchaText } = ctx.request.body

			if (!username || !password) {
				ctx.body = {
					code: 500,
					data: null,
					msg: '缺少用户名和密码参数！'
				}
				return
			}

            if (!captchaId || !captchaText) {
				ctx.body = {
					code: 500,
					data: null,
					msg: '缺少验证码参数！'
				}
				return
			}

            // 校验验证码
            let checkResult = await UserController.verifyCaptcha(captchaId, captchaText)

            if (checkResult.code === 200) {
                // 验证码校验成功，开始下一步根据用户账号查找用户信息
                const user = await User.findByUsername(username)

                if (!user) {
                    ctx.body = {
                        code: 500,
                        data: null,
                        msg: '登录账号错误！'
                    }
                    return
                }

                // 验证密码
			    const isValidPassword = await bcrypt.compare(password, user.password)

                if (!isValidPassword) {
                    ctx.body = {
                        code: 500,
                        data: null,
                        msg: '登录密码错误！'
                    }
                    return
                }

                // 生成访问资源 token，将过期时间设置为 2 小时
                const accessToken = jwt.sign(
                    { userId: user.id, username: user.username },
                    process.env.JWT_SECRET || secretKey,
                    { expiresIn: '2h' }
                )

                // 生成刷新令牌，将过期时间设置为 1 天
                const refreshToken = jwt.sign(
                    { userId: user.id, username: user.username },
                    process.env.JWT_SECRET || secretKey,
                    { expiresIn: '1d' }
                )

                // 将两个 Token 存储到 Redis，分别设置过期时间
                await redisClient.setEx(`accessToken:${user.id}:${accessToken}`, 2 * 60 * 60, 'valid')
                await redisClient.setEx(`refreshToken:${user.id}:${refreshToken}`, 1 * 24 * 60 * 60, 'valid')
                await User.login(user.id)

                ctx.body = {
                    code: 200,
                    msg: '登录成功！',
                    data: { accessToken, refreshToken, createTime: moment().format('YYYY-MM-DD HH:mm:ss') }
                }
            } else {
                // 验证码校验失败
                ctx.body = checkResult
            }
		} catch (error) {
			ctx.body = {
				code: 500,
				data: null,
				msg: '服务器错误，请联系管理员：' + error
			}
		}
	}

    /**
     * @swagger
     * /user/refreshToken:
     *   post:
     *     summary: 刷新令牌
     *     description: 刷新令牌
     *     tags: [登录]
     *     parameters:
     *       - name: refreshToken
     *         type: string
     *         required: true
     *         description: 刷新令牌
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: {
     *                      accessToken: '访问数据token',
     *                      refreshToken: '刷新令牌token'
     *                   }
     *                 msg:
     *                   type: string
     *                   example: "登录成功！"
     */
    // 刷新令牌
    static async refreshToken(ctx) {
        const { refreshToken } = ctx.request.body

        if (!refreshToken) {
            ctx.body = {
                code: 500,
                data: null,
                msg: '缺少刷新令牌参数！'
            }
        } else {
            try {
                // 检查 Redis 中是否存在此 refreshToken
                const inBlacklist = await redisClient.get(`blacklist:${refreshToken}`)

                if (inBlacklist) {
                    ctx.body = { code: 401, data: null, msg: '此令牌已失效！' }
                    return
                }

                // 验证 refreshToken
                const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET || 'your-secret-key')
                const accessToken = ctx.headers.authorization.split(' ')[1]

                if (!decoded) {
                    ctx.body = { code: 401, data: null, msg: '无效的令牌！' }
                    return
                }

                // 验证成功，将之前的令牌加入黑名单
                await redisClient.setEx(`blacklist:${accessToken}`, 24 * 60 * 60, 'true')
                await redisClient.setEx(`blacklist:${refreshToken}`, 24 * 60 * 60, 'true')

                // 生成访问资源 token，将过期时间设置为 2 小时
                const newAccessToken = jwt.sign(
                    { userId: decoded.userId, username: decoded.username },
                    process.env.JWT_SECRET || secretKey,
                    { expiresIn: '2h' }
                )

                // 生成刷新令牌，将过期时间设置为 1 天
                const newRefreshToken = jwt.sign(
                    { userId: decoded.userId, username: decoded.username },
                    process.env.JWT_SECRET || secretKey,
                    { expiresIn: '1d' }
                )

                // 将两个 Token 存储到 Redis，分别设置过期时间
                await redisClient.setEx(`accessToken:${decoded.userId}:${newAccessToken}`, 2 * 60 * 60, 'valid')
                await redisClient.setEx(`refreshToken:${decoded.userId}:${newRefreshToken}`, 1 * 24 * 60 * 60, 'valid')

                ctx.body = {
                    code: 200,
                    data: {
                        accessToken: newAccessToken,
                        refreshToken: newRefreshToken,
                        createTime: moment().format('YYYY-MM-DD HH:mm:ss')
                    },
                    msg: 'token 刷新成功！'
                }
            } catch (error) {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '服务器错误，请联系管理员：' + error
                }
            }
        }
    }

    // 验证验证码
    static async verifyCaptcha(captchaId, code) {
        try {
            if (!captchaId || !code) {
                return {
                    code: 400,
                    data: null,
                    msg: '参数错误！'
                }
            }

            // 从 Redis 获取存储的验证码
            const storedCode = await redisClient.get(`captcha:${captchaId}`)

            if (!storedCode) {
                return {
                    code: 500,
                    data: null,
                    msg: '验证码已过期！'
                }
            }

            // 比较验证码（不区分大小写）
            if (storedCode.toLowerCase() !== code.toLowerCase()) {
                return {
                    code: 500,
                    data: null,
                    msg: '验证码错误！'
                }
            }

            // 验证成功后删除验证码
            await redisClient.del(`captcha:${captchaId}`)
            
            // 验证成功
            return {
                code: 200,
                data: null,
                msg: '验证码正确！'
            }
        } catch (error) {
            return {
                code: 500,
                data: null,
                msg: '验证失败！'
            }
        }
    }

    /**
     * @swagger
     * /user/getUserInfo:
     *   get:
     *     summary: 获取用户信息接口
     *     description: 用户信息
     *     tags: [用户信息]
     *     security:
     *       - BearerAuth: [] # 需要 Bearer 认证
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: {
     *                      id: 12,
     *                      username: 'admin',
     *                      nickname: '管理员',
     *                      avatar: 'asdfasdasd1688607695.png',
     *                      companyName: 'xx企业',
     *                      email: '131115455@163.com',
     *                      sex: 0,
     *                      job: '前端',
     *                      phone: '15284575685',
     *                   }
     *                 msg:
     *                   type: string
     *                   example: "用户信息获取成功！"
     */
    // 获取用户信息
    static async getUserInfo(ctx) {
        try {
            const { userId } = ctx.state.user
            const result = await User.findByUserId(userId)

            if (result) {
                if (result.phone) {
                    result.phone = desensitizePhone(result.phone)
                }

                ctx.body = {
                    code: 200,
                    data: result,
                    msg: '用户信息查询成功！'
                }
            } else {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '用户信息查询失败！'
                }
            }
        } catch (error) {
            ctx.status = 500
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
        }
    }

    /**
     * @swagger
     * /user/logout:
     *   post:
     *     summary: 退出登录
     *     description: 退出登录
     *     tags: [退出登录]
     *     parameters:
     *       - name: refreshToken
     *         schema:
     *           type: string
     *         required: true
     *         description: 刷新令牌
     *     security:
     *       - BearerAuth: [] # 需要 Bearer 认证
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: null
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "退出成功！"
     */
	// 退出登录
	static async logout(ctx) {
		try {
            const refreshToken = ctx.request.body.refreshToken
			const accessToken = ctx.headers.authorization.split(' ')[1]
			const decoded = jwt.verify(accessToken, process.env.JWT_SECRET)

            if (!decoded) {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: 'Token 无效！'
                }
                return
            }

            if (!refreshToken) {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '缺少核心参数！'
                }
                return
            }

			// 将两个 Token 加入黑名单（24小时）
			await redisClient.setEx(`blacklist:${accessToken}`, 24 * 60 * 60, 'true')
            await redisClient.setEx(`blacklist:${refreshToken}`, 24 * 60 * 60, 'true')

            ctx.body = {
                code: 200,
                data: null,
                msg: '退出成功！'
            }
		} catch (error) {
            ctx.body = {
                code: 200,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
		}
	}

    /**
     * @swagger
     * /user/updateUserInfo:
     *   put:
     *     summary: 更新用户信息
     *     description: 更新用户信息
     *     tags: [更新用户信息]
     *     parameters:
     *       - name: job
     *         type: string
     *         required: false
     *         description: 职业
     *       - name: nickName
     *         type: string
     *         required: false
     *         description: 昵称
     *       - name: companyName
     *         type: string
     *         required: false
     *         description: 用户所在企业名称
     *       - name: sex
     *         type: string
     *         required: true
     *         description: 性别：0 男，1 女
     *       - name: introduction
     *         type: string
     *         required: false
     *         description: 个人介绍
     *       - name: email
     *         type: string
     *         required: false
     *         description: 邮箱
     *       - name: avatar
     *         type: string
     *         required: false
     *         description: 头像（头像上传成功后，后端返回的图片地址）
     *     security:
     *       - BearerAuth: [] # 需要 Bearer 认证
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: null
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "用户信息更新成功！"
     */
    // 更新用户信息
    static async updateUserInfo(ctx) {
        const { userId } = ctx.state.user
        const { nickName, avatar, sex, email, job, companyName, introduction } = ctx.request.body

        try {
            const result = await User.updateUserInfo({ id: userId, nickName, avatar, sex, email, job, companyName, introduction })

            if (!result) {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '用户信息更新失败！'
                }
                return
            }

            ctx.body = {
                code: 200,
                data: null,
                msg: '用户信息更新成功！'
            }
        } catch (error) {
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
        }
    }

    /**
     * @swagger
     * /user/follow:
     *   post:
     *     summary: 关注用户接口
     *     description: 关注用户
     *     tags: [关注用户]
     *     parameters:
     *       - name: followId
     *         type: number
     *         required: true
     *         description: 关注的这个用户的id
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example:
     *                 msg:
     *                   type: string
     *                   example: "关注成功！"
     */
    // 关注用户
    static async follow(ctx) {
        const { followId } = ctx.request.body
        const { userId } = ctx.state.user

        try {
            const result = await User.follow(userId, followId)

            if (result) {
                if (result.code === 500) {
                    return ctx.body = result
                }

                ctx.body = {
                    code: 200,
                    data: null,
                    msg: '关注成功！'
                }
            } else {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '关注用户失败！'
                }
            }
        } catch (error) {
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
        }
    }

    /**
     * @swagger
     * /user/cancelFollow:
     *   delete:
     *     summary: 取消关注用户接口
     *     description: 取消关注用户
     *     tags: [取消关注用户]
     *     parameters:
     *       - name: followId
     *         type: number
     *         required: true
     *         description: 关注的这个用户的id
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example:
     *                 msg:
     *                   type: string
     *                   example: "取消关注成功！"
     */
    // 取消关注
    static async cancelFollow(ctx) {
        const { followId } = ctx.request.body
        const { userId } = ctx.state.user

        try {
            const result = await User.cancelFollow(userId, followId)

            if (result) {
                if (result.code === 500) {
                    return ctx.body = result
                }

                ctx.body = {
                    code: 200,
                    data: null,
                    msg: '取消关注成功！'
                }
            } else {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '取消关注失败！'
                }
            }
        } catch (error) {
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
        }
    }

    /**
     * @swagger
     * /user/delAccount:
     *   post:
     *     summary: 注销账号
     *     description: 注销账号
     *     tags: [注销账号]
     *     security:
     *       - BearerAuth: [] # 需要 Bearer 认证
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: null
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "注销成功，3 天内重新登录，可取消注销！"
     */
    // 注销账号
    static async delAccount(ctx) {
        const userId = ctx.state.user.userId
        const token = ctx.headers.authorization.split(' ')[1]
        const decoded = jwt.verify(token, process.env.JWT_SECRET)

        try {
            if (!decoded) {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: 'Token 令牌无效，注销失败！'
                }
                return
            }

            const result = await User.delAccount(userId)

            if (result) {
                // 将 Token 加入黑名单（24小时）
			    await redisClient.setEx(`blacklist:${token}`, 24 * 60 * 60, 'true')

                ctx.body = {
                    code: 200,
                    data: null,
                    msg: '注销成功，3 天内重新登录，可取消注销！'
                }
            } else {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '注销失败！'
                }
            }
        } catch (error) {
            ctx.status = 500
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
        }
    }

    /**
     * @swagger
     * /user/sendEmailCode:
     *   post:
     *     summary: 发送邮箱验证码
     *     description: 发送邮箱验证码
     *     tags: [发送邮箱验证码]
     *     parameters:
     *       - name: email
     *         type: string
     *         required: true
     *         description: 你收取验证码的邮箱账号（目前只支持 163 邮箱）
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example:
     *                 msg:
     *                   type: string
     *                   example: "验证码发送成功，请在5分钟内前往163邮箱查看！"
     */
    // 发送邮箱验证码接口
    static async sendEmailCode(ctx) {
        const { email } = ctx.request.body

        // 1. 验证邮箱格式
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
            ctx.body = { code: 500, data: null, msg: '邮箱格式不正确！' }
            return
        }

        // 2. 检查发送频率（防止滥用）
        const lastSentKey = `last_sent:${email}`
        const lastSent = await redisClient.get(lastSentKey)
        if (lastSent && Date.now() - parseInt(lastSent) < 60000) {
            ctx.body = { code: 500, data: null, msg: '请求过于频繁，请1分钟后再试！' }
            return
        }

        // 3. 生成6位验证码
        const code = Math.floor(100000 + Math.random() * 900000).toString()
        const expiresIn = 5 * 60 // 5分钟

        // 4. 存储到Redis
        const codeKey = getCodeKey(email + `:reset_password`)
        await redisClient.setEx(codeKey, expiresIn, code)
        await redisClient.setEx(lastSentKey, 60, Date.now().toString())

        // 5. 发送邮件
        const success = await sendVerificationEmail(email, code, 'reset_password')

        if (success) {
            ctx.body = { code: 200, data: null, msg: '验证码发送成功，请在5分钟内前往163邮箱查看！' }
        } else {
            ctx.body = { code: 500, data: null, msg: '验证码发送失败，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/resetPassword:
     *   post:
     *     summary: 重置密码
     *     description: 重置密码
     *     tags: [重置密码]
     *     parameters:
     *       - name: email
     *         type: string
     *         required: true
     *         description: 你收取验证码的邮箱账号（目前只支持 163 邮箱）
     *       - name: code
     *         type: string
     *         required: true
     *         description: 验证码
     *       - name: password
     *         type: string
     *         required: true
     *         description: 新密码
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example:
     *                 msg:
     *                   type: string
     *                   example: "密码重置成功，请重新登录！"
     */
    // 重置密码
    static async resetPassword(ctx) {
        const { email, code, password } = ctx.request.body
        const { userId } = ctx.state.user

        try {
            const key = getCodeKey(email + ':reset_password') // 生成相同的键名
            const storedCode = await redisClient.get(key) // 从Redis获取

            
            // 校验验证码
            if (storedCode === code) {
                await redisClient.del(key) // 删除验证码

                // 将新密码加密
                let newPwd = bcrypt.hashSync(password, 10)
                let result = await User.resetPassword(userId, newPwd)

                if (result) {
                    ctx.body = {
                        code: 200,
                        data: null,
                        msg: "密码重置成功"
                    }
                    return
                }

                ctx.body = {
                    code: 500,
                    data: null,
                    msg: "密码重置失败！"
                }
            } else {
                ctx.body = {
                    code: 500,
                    data: null,
                    msg: '验证码错误，密码重置失败！'
                }
            }
        } catch (err) {
            ctx.status = 500
            ctx.body = {
                code: 500,
                data: null,
                msg: '服务器错误，请联系管理员！'
            }
        }
    }

    /**
     * @swagger
     * /user/bindPhone:
     *   post:
     *     summary: 绑定手机号
     *     description: 绑定手机号
     *     tags: [绑定手机号]
     *     parameters:
     *       - name: phone
     *         type: string
     *         required: true
     *         description: 你要绑定的手机号
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example:
     *                 msg:
     *                   type: string
     *                   example: "绑定成功！"
     */
    // 绑定手机号
    static async bindPhone(ctx) {
        const { phone } = ctx.request.body
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        if (!phone) {
            ctx.body = { code: 500, data: null, msg: '缺少关键参数，请检查！' }
            return
        }

        try {
            let result = await User.bindPhone(userId, phone)

            if (result.code === 500) {
                ctx.body = result
                return
            }

            ctx.body = { code: 200, data: null, msg: '绑定成功！' }
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/findFollowState:
     *   get:
     *     summary: 查询用户是否关注过
     *     description: 查询用户是否关注过
     *     tags: [查询用户是否关注过]
     *     parameters:
     *       - name: followId
     *         type: number
     *         required: true
     *         description: 这篇文章作者的id
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: "true： 已关注, false: 未关注"
     *                 msg:
     *                   type: string
     *                   example: "此作者已关注！"
     */
    // 查询用户是否关注过
    static async findFollowState(ctx) {
        const { followId } = ctx.request.query
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        if (!followId) {
            ctx.body = { code: 500, data: null, msg: '缺少关键参数，请检查！' }
            return
        }

        try {
            let result = await User.findFollowState(followId, userId)
            ctx.body = result
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/getChatRecord:
     *   get:
     *     summary: 查询聊天记录
     *     description: 查询聊天记录
     *     tags: [查询聊天记录]
     *     parameters:
     *       - name: recipientId
     *         type: number
     *         required: true
     *         description: 你和谁聊（这篇文章作者的id）
     *       - name: currentPage
     *         type: number
     *         required: true
     *         description: 当前页
     *       - name: pageSize
     *         type: number
     *         required: true
     *         description: 每页显示的数据条数
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: {
     *                      "chatId": "聊天记录id", 
     *                      "senderId": "发送人id",
     *                      "recipientId": "接收人id",
     *                      "content": "聊天内容",
     *                      "type": "消息类型，1 聊天消息，2 系统消息",
     *                      "state": "消息状态（0 未读，1 已读）",
     *                      "createTime": "消息创建时间",
     *                      "isRevoke": "是否可以撤回（0 可以撤回，1 不可以撤回，消息发送成功后1分钟内可以撤回，1分钟后自动改为不可撤回状态）",
     *                      "senderUsername": "发送人账号",
     *                      "senderNickName": "发送人昵称",
     *                      "senderAvatar": "发送人头像",
     *                   }
     *                 msg:
     *                   type: string
     *                   example: "查询成功！"
     */
    // 查询聊天记录
    static async getChatRecord(ctx) {
        const { recipientId, currentPage, pageSize } = ctx.request.query
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        if (!recipientId || !currentPage || !pageSize) {
            ctx.body = { code: 500, data: null, msg: '缺少关键参数，请检查！' }
            return
        }

        try {
            let result = await User.getChatRecord(userId, recipientId, currentPage, pageSize)
            ctx.body = result
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/updateRevokeState:
     *   put:
     *     summary: 修改撤回状态
     *     description: 将聊天内容发送超过 1 分钟的消息置为不可撤回，is_revoke = 1
     *     tags: [修改撤回状态]
     *     parameters:
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "修改成功！"
     */
    // 将聊天内容发送超过 1 分钟的消息置为不可撤回，is_revoke = 1
    static async updateRevokeState(ctx) {
        const { userId } = ctx.state.user

        try {
            let result = await User.updateRevokeState(userId)
            ctx.body = result
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/getNoReadMsgList:
     *   get:
     *     summary: 查询用户未读消息列表
     *     description: 查询用户未读消息列表
     *     tags: [查询用户未读消息列表]
     *     parameters:
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "查询成功！"
     */
    // 查询用户未读消息列表
    static async getNoReadMsgList(ctx) {
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        try {
            let result = await User.getNoReadMsgList(userId)

            if (result) {
                ctx.body = { code: 200, data: result, msg: '查询成功！' }
            } else {
                ctx.body = { code: 500, data: null, msg: '查询失败！' }
            }
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/getNoReadMsgCount:
     *   get:
     *     summary: 查询用户未读消息总数
     *     description: 查询用户未读消息总数
     *     tags: [查询用户未读消息总数]
     *     parameters:
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "查询成功！"
     */
    // 查询用户未读消息总数
    static async getNoReadMsgCount(ctx) {
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        try {
            let result = await User.getNoReadMsgCount(userId)

            if (result) {
                ctx.body = { code: 200, data: result.total, msg: '查询成功！' }
            } else {
                ctx.body = { code: 500, data: null, msg: '查询失败！' }
            }
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/updateMsgState:
     *   put:
     *     summary: 批量修改用户消息状态
     *     description: 批量修改用户消息状态，将未读设为已读，这是根据消息id批量修改
     *     tags: [批量修改用户消息状态]
     *     parameters:
     *       - name: msgIds
     *         type: string
     *         required: true
     *         description: 消息id集合，多个消息用 ‘,’ 逗号拼接
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "修改成功！"
     */
    // 批量修改用户消息状态（将未读设为已读）
    static async updateMsgState(ctx) {
        const { userId } = ctx.state.user
        const { msgIds } = ctx.request.body

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        if (!msgIds) {
            ctx.body = { code: 500, data: null, msg: '参数异常，请检查！' }
            return
        }

        try {
            let result = await User.updateMsgState(userId, msgIds)

            if (result) {
                ctx.body = { code: 200, data: null, msg: '修改成功！' }
            } else {
                ctx.body = { code: 500, data: null, msg: '修改失败！' }
            }
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/updateFriendMsgState:
     *   put:
     *     summary: 将好友发送的消息，设为已读
     *     description: 当用户进入私信界面，用户（登陆人，消息接收人）与当前好友的聊天消息中，将当前好友（发送人）的消息设为已读
     *     tags: [将好友发送的消息，设为已读]
     *     parameters:
     *       - name: senderId
     *         type: string
     *         required: true
     *         description: 好友id，消息发送人
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "修改成功！"
     */

    // 将好友发送的消息，设为已读
    // 当用户进入私信界面，用户（登陆人，消息接收人）与当前好友的聊天消息中，将当前好友（发送人）的消息设为已读
    static async updateFriendMsgState(ctx) {
        const { senderId } = ctx.request.body
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        if (!senderId) {
            ctx.body = { code: 500, data: null, msg: '参数异常，请检查！' }
            return
        }

        try {
            let result = await User.updateFriendMsgState(senderId, userId)
            ctx.body = result
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系' }
        }
    }

    /**
     * @swagger
     * /user/revokeMsg:
     *   delete:
     *     summary: 撤回消息
     *     description: 撤回消息（只能撤回自己消息）
     *     tags: [撤回消息]
     *     parameters:
     *       - name: msgId
     *         type: string
     *         required: true
     *         description: 消息id
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: object
     *                   example: null
     *                 msg:
     *                   type: string
     *                   example: "撤回成功！"
     */
    // 撤回消息
    static async revokeMsg(ctx) {
        const { msgId } = ctx.request.body
        const { userId } = ctx.state.user

        if (!userId) {
            ctx.body = { code: 500, data: null, msg: '请登录！' }
            return
        }

        if (!msgId) {
            ctx.body = { code: 500, data: null, msg: '参数异常，请检查！' }
            return
        }

        try {
            let result = await User.revokeMsg(userId, msgId)

            if (result) {
                ctx.body = result
            } else {
                ctx.body = { code: 500, data: null, msg: '撤回失败！' }
            }
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }

    /**
     * @swagger
     * /user/getFriendList:
     *   get:
     *     summary: 查询登录人好友
     *     description: 查询登录人好友（只有互相关注才能算好友）
     *     tags: [查询登录人好友]
     *     parameters:
     *     responses:
     *       200:
     *         description: 成功响应
     *         content:
     *           application/json:
     *             schema:
     *               type: object
     *               properties:
     *                 code:
     *                   type: number,
     *                   example: 200
     *                 data:
     *                   type: array
     *                   example: [
     *                     {
     *                       avatar: "好友头像",
     *                       isOwnLastMessage: "如果最后一条消息是当前用户发送的，返回 1 (true)，如果最后一条消息是好友发送的，返回 0 (false)",
     *                       isReadState: "0 未读，1 已读",
     *                       lastMessage: "最后发送的消息内容",
     *                       lastMessageSender: "最后发送消息的人id",
     *                       lastMessageTime: "最后发送消息的时间",
     *                       nickName: "好友昵称",
     *                       userId: "好友id",
     *                       username: "好友账号",
     *                       noReadCount: "好友未读消息数量"
     *                     }
     *                   ]
     *                 msg:
     *                   type: string
     *                   example: "查询成功！"
     */
    // 查询好友列表
    static async getFriendList(ctx) {
        const { userId } = ctx.state.user

        try {
            let result = await User.getFriendList(userId)
            ctx.body = result
        } catch (error) {
            ctx.body = { code: 500, data: null, msg: '服务器错误，请联系管理员！' }
        }
    }
}

module.exports = UserController
